home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright 1992, 1993, 1994, Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
- * the contents of this file may not be disclosed to third parties, copied or
- * duplicated in any form, in whole or in part, without the prior written
- * permission of Silicon Graphics, Inc.
- *
- * RESTRICTED RIGHTS LEGEND:
- * Use, duplication or disclosure by the Government is subject to restrictions
- * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
- * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
- * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
- * rights reserved under the Copyright Laws of the United States.
- */
- /*
- * Copyright (C) 1992 Silicon Graphics, Inc.
- *
- _______________________________________________________________________
- ______________ S I L I C O N G R A P H I C S I N C . ____________
- |
- | $Revision: 1.0000 $
- |
- | File: player.c++
- | Purpose: opens a gl window, and creates and animation based upon
- | the inventor models and animation file input
- |
- | Author(s) : Kevin Goldsmith
- |
- ______________ S I L I C O N G R A P H I C S I N C . ____________
- _______________________________________________________________________
- */
-
-
-
-
- #include <string.h>
- #include <unistd.h>
- #include <getopt.h>
- #include <stdio.h>
- #include <stdlib.h>
-
- #include <Inventor/SoDB.h>
- #include <Inventor/Xt/SoXt.h>
- #include <Inventor/Xt/SoXtRenderArea.h>
- #include <Inventor/nodes/SoSeparator.h>
- #include <Inventor/nodes/SoPerspectiveCamera.h>
- #include <Inventor/nodes/SoPointLight.h>
- #include <Inventor/nodes/SoLabel.h>
- #include <Inventor/actions/SoWriteAction.h>
- #include <Inventor/actions/SoSearchAction.h>
- #include <Inventor/SbLinear.h>
- #include <Inventor/SoOffscreenRenderer.h>
-
- #define MAX_KEY_FRAMES 20
-
- // these are global variables for some important stuff
- static char *filename = NULL;
- static char *animfile = NULL;
-
- // these are globals for flags and stuff
- static int saveNum; // saves the start frame #
- static int save = 0; // says if we are saving to disk or not
- static int frameNum; // current frame number
- static int currentkey; // current keyframe number
- static int printenv = 0; // do we print out an env file when done?
- static int startFrame = 0; // the start frame
- static int endFrame = 0; // the end frame
- static int START = 0; // did the user give us a start frame?
- static int END = 0; // did the user give us an end frame?
- static int camLinear = 0; // are we linearly interpolating?
- static int verbose = 0; // are we chatty?
- static int xwidth = 640; // width of the screen
- static int yheight = 480; // height of the screen
- static int naptime = 0;
-
- // structure for splines
- typedef struct {
- double min_x, max_x; /* min and max domain points */
- long n; /* number of domain points */
- double *x; /* array of domain points */
- double *a; /* spline coefficients */
- double *b;
- double *c;
- double *d;
- } SPLINE;
-
- // global splines for camera movement
- SPLINE *PosSplineX;
- SPLINE *PosSplineY;
- SPLINE *PosSplineZ;
-
- //key frame structure
- struct keyframe {
- int frame;
- SbVec3f position;
- SbVec3f axis;
- float angle;
- } keyFrames[MAX_KEY_FRAMES];
-
- // global number of keyframes
- int keyframenum;
-
-
-
- //
- // FILE READING STUFF!!!
- //
-
-
- // better way to open a file
- static FILE *OPEN(const char *filename, char *type)
- {
- FILE *fp;
- if ((fp = fopen(filename, type)) == NULL) {
- fprintf(stderr, "Couldn't open %s\n", filename);
- exit(1);
- }
- return fp;
- }
-
-
- // reads in the animation file, not very smart, will not check for errors
- void readFile(const char *animfile)
- {
- FILE *fp;
- int tempframe;
- float temp[7];
-
- keyframenum = 0;
- fp = OPEN (animfile, "r");
- while(1) {
- if (fscanf(fp, "%d %f %f %f %f %f %f %f", &tempframe, &temp[0],
- &temp[1], &temp[2], &temp[3], &temp[4], &temp[5],
- &temp[6]) == EOF)
- break;
- keyFrames[keyframenum].frame = tempframe;
- keyFrames[keyframenum].position = SbVec3f(temp[0], temp[1], temp[2]);
- keyFrames[keyframenum].axis = SbVec3f(temp[3], temp[4], temp[5]);
- keyFrames[keyframenum].angle = temp[6];
- ++keyframenum;
- }
- fclose(fp);
- if (verbose) fprintf(stderr, "%d keyframes read\n", keyframenum);
- }
-
-
- //
- // Read a file given a filename and return a separator containing all
- // of the stuff in the file.
- // stolen mostly from Gavin Bell
- //
- SoSeparator *
- readivFile(const char *filename)
- {
- SoInput in;
- if (filename != NULL)
- {
- if (in.openFile(filename) == FALSE)
- {
- fprintf(stderr, "Could not open file %s\n", filename);
- return NULL;
- }
- }
-
- SoSeparator *graph = new SoSeparator;
- graph->ref();
-
- //
- // Keep on reading until there are no more nodes to read
- //
- SoNode *root;
- do
- {
- int read_ok = SoDB::read(&in, root);
-
- if (!read_ok)
- {
- fprintf(stderr, "Error reading file\n");
- graph->unref();
- return NULL;
- }
- else if (root != NULL) graph->addChild(root);
-
- } while (root != NULL);
- in.closeFile();
-
- //
- // Try to avoid creating extra separators; if this scene graph
- // already has exactly one separator at the top, use it. This
- // will avoid an explosion of separators at the top of scenes that
- // would otherwise occur if we automatically created a new
- // separator every time a scene graph was read.
- //
- if (graph->getNumChildren() == 1 &&
- graph->getChild(0)->isOfType(SoSeparator::getClassTypeId()))
- {
- SoSeparator *result = (SoSeparator *)graph->getChild(0);
- result->ref(); // Note the order here!
- graph->unref();
-
- result->unrefNoDelete();
- return result;
- }
-
- graph->unrefNoDelete();
- return graph;
-
- }
-
-
-
-
-
-
-
-
-
- //
- // SPLINE STUFF!!!!!
- // I stole these mostly from Drew Olbrich
- //
-
- SPLINE *spline_new(int n, double *x, double *f)
- {
- SPLINE *spline;
- int i;
- double t;
- double *h;
- double *u;
- double *ta;
- double *td;
- double *tb;
- double *tf;
-
- if (n < 3)
- return NULL;
-
- spline = (SPLINE *) malloc(sizeof(SPLINE));
- if (spline == NULL)
- {
- fprintf(stderr, "Could not allocate spline.\n");
- exit(-1);
- }
-
- spline->x = (double *) malloc((n*sizeof(double)));
- if (spline->x == NULL)
- {
- fprintf(stderr, "Could not allocate spline data.\n");
- exit(-1);
- }
- for (i = 0; i < n; i++)
- spline->x[i] = x[i];
-
- spline->n = n;
- spline->min_x = x[0];
- spline->max_x = x[n - 1];
-
- spline->a = (double *) malloc(n*sizeof(double));
- spline->b = (double *) malloc(n*sizeof(double));
- spline->c = (double *) malloc(n*sizeof(double));
- spline->d = (double *) malloc(n*sizeof(double));
-
- if (spline->d == NULL)
- {
- fprintf(stderr, "Could not allocate spline coefficient data.\n");
- exit(-1);
- }
-
- h = (double *) malloc((n+1)*sizeof(double));
- u = (double *) malloc((n+1)*sizeof(double));
-
- ta = (double *) malloc((n+1)*sizeof(double));
- td = (double *) malloc((n+1)*sizeof(double));
- tb = (double *) malloc((n+1)*sizeof(double));
- tf = (double *) malloc((n+1)*sizeof(double));
-
- if (tf == NULL)
- {
- fprintf(stderr, "Could not allocate temporary spline data.\n");
- exit(-1);
- }
-
- for (i = 0; i < n - 1; i++) {
- h[i] = x[i + 1] - x[i];
- u[i] = (f[i + 1] - f[i])/h[i];
- spline->a[i] = f[i];
- }
-
- for (i = 0; i < (n - 2); i++)
- td[i] = 2.0*(h[i] + h[i + 1]);
-
- for (i = 0; i < (n - 2); i++)
- ta[i] = tb[i] = h[i + 1];
-
- for (i = 0; i < (n - 2); i++)
- tf[i] = 3.0*(u[i + 1] - u[i]);
-
- for (i = 1; i < (n - 2); i++)
- {
- t = ta[i - 1]/td[i - 1];
- td[i] = td[i] - t*tb[i - 1];
- tf[i] = tf[i] - t*tf[i - 1];
- }
-
- spline->c[0] = 0.0;
- spline->c[n - 1] = 0.0;
- spline->c[n - 2] = tf[n - 3]/td[n - 3];
- for (i = (n - 4); i >= 0; i--)
- spline->c[i + 1] = (tf[i] - tb[i]*spline->c[i + 2])/td[i];
-
- for (i = 0; i < (n - 1); i++) {
- spline->b[i] = u[i] - h[i]*(2.0*spline->c[i] + spline->c[i + 1])/3.0;
- spline->d[i] = (spline->c[i + 1] - spline->c[i])/(h[i]*3.0);
- }
-
- free(h);
- free(u);
-
- free(ta);
- free(td);
- free(tb);
- free(tf);
-
- return spline;
- }
-
-
-
- double spline_eval(SPLINE *spline, double t)
- {
- int i;
- int high, low, mid;
- double result, qq;
-
- if (spline == NULL)
- return 0.0;
-
- if ((t < spline->min_x) || (t > spline->max_x))
- return 0.0;
-
- low = 0;
- high = (int) spline->n - 1;
- i = -1;
- while (i == -1 && low <= high) {
- mid = (low + high) >> 1;
- if (t < spline->x[mid])
- high = mid - 1;
- else if (mid + 1 < spline->n && t > spline->x[mid + 1])
- low = mid + 1;
- else
- i = mid;
- }
- qq = t - spline->x[i];
-
- result = spline->a[i]
- + qq*(spline->b[i] + qq*(spline->c[i] + qq*spline->d[i]));
-
- return result;
- }
-
- // creates the splines for the animation
- void
- createSplines()
- {
- double a[MAX_KEY_FRAMES], x[MAX_KEY_FRAMES],
- y[MAX_KEY_FRAMES], z[MAX_KEY_FRAMES];
- float tempx, tempy, tempz;
-
- for (int i = 0; i < keyframenum; i++) {
- a[i] = (double) keyFrames[i].frame;
- keyFrames[i].position.getValue(tempx, tempy, tempz);
- x[i] = (double) tempx;
- y[i] = (double) tempy;
- z[i] = (double) tempz;
- }
-
- PosSplineX = spline_new(keyframenum, a, x);
- PosSplineY = spline_new(keyframenum, a, y);
- PosSplineZ = spline_new(keyframenum, a, z);
- }
-
-
-
-
-
-
-
-
-
-
-
- // this is where the light and the camera are updated
- void Animate(SoCamera *camera, SoPointLight *light)
- {
- if (verbose) fprintf(stderr, "rendering frame #%d: ",frameNum);
-
- if (!camLinear) {
- // if we are using splines
- camera->position = SbVec3f((float) spline_eval(PosSplineX,frameNum),
- (float) spline_eval(PosSplineY,frameNum),
- (float) spline_eval(PosSplineZ,frameNum));
- } else {
- // otherwise
- float t = (float) (frameNum - keyFrames[currentkey].frame) /
- (float) (keyFrames[currentkey + 1].frame -
- keyFrames[currentkey].frame);
- float x,y,z,x2,y2,z2;
-
- keyFrames[currentkey].position.getValue(x,y,z);
- keyFrames[currentkey + 1].position.getValue(x2,y2,z2);
- camera->position = SbVec3f((x + t * (x2 - x)),
- (y + t * (y2 - y)),
- (z + t * (z2 - z)));
- }
-
- light->location = camera->position;
- // to be easy, I am just using a pointlight as a headlight, and
- // having it be in the exact same place as the camera.
- // things would work faster, if I was using a directional light
- // facing in the same direction as the camera
-
-
- // are we up to the next keyframe?
- if (keyFrames[currentkey + 1].frame <= frameNum) currentkey++;
-
-
- if (currentkey < keyframenum - 1) {
- // dont bother if we are done
-
- SbRotation last, next;
- float t;
-
- last = SbRotation(keyFrames[currentkey].axis,
- keyFrames[currentkey].angle);
- next = SbRotation(keyFrames[currentkey+1].axis,
- keyFrames[currentkey+1].angle);
- t = (float) (frameNum - keyFrames[currentkey].frame) /
- (float) (keyFrames[currentkey + 1].frame
- - keyFrames[currentkey].frame);
-
- camera->orientation.setValue(SbRotation::slerp(last, next, t));
- }
-
- ++frameNum; // move onto the next frame
- }
-
-
-
-
-
-
- // parses the command line for user stuff
- static void
- parseCommandLine(int argc, char **argv)
- {
- int err = 0; // Flag: error in options?
- int c;
-
- while (( c = getopt(argc, argv, "ls:e:pq:vx:y:n:")) != -1)
- {
- switch(c)
- {
- case 'l':
- camLinear = 1;
- break;
- case 's':
- START = 1;
- startFrame = atoi(optarg);
- break;
- case 'e':
- END = 1;
- endFrame = atoi(optarg);
- break;
- case 'p':
- printenv = 1;
- fprintf(stderr, "printing out env file at end\n");
- break;
- case 'q':
- saveNum = atoi(optarg);
- save = 1;
- break;
- case 'v':
- verbose = 1;
- break;
- case 'x':
- xwidth = atoi(optarg);
- break;
- case 'y':
- yheight = atoi(optarg);
- break;
- case 'n':
- naptime = atoi(optarg);
- break;
- default:
- err = 1;
- break;
- }
-
- }
-
- if (optind+2 != argc) err = 1;
-
- filename = argv[optind];
- animfile = argv[optind + 1];
-
- if (err)
- {
- fprintf(stderr, "Usage: %s [-p] [-v] [-q num] [-l] [-s start]",
- " [-e end] [-x width] [-y height] [-n clicks]",
- " inventorfilename animationfilename\n",
- argv[0]);
- fprintf(stderr, "-p prints out an environment file at the end of animation\n");
- fprintf(stderr, "-v turns on verbose mode\n");
- fprintf(stderr, "-q saves the animation starting at frame num\n");
- fprintf(stderr, "-l moves the camera linearly between control points\n");
- fprintf(stderr, "-s starts the animation at frame num\n");
- fprintf(stderr, "-e ends the animation at frame num\n");
- fprintf(stderr, "-x set the width of the animation\n");
- fprintf(stderr, "-y set the height of the animation\n");
- fprintf(stderr, "-n set the ammount of ticks pausing between frames\n");
- exit(99);
- }
- }
-
-
- //
- // at last we made it to MAIN
- //
- main( int argc, char **argv )
- {
- SoCamera *camera = NULL;
- SoPointLight *light = NULL;
-
- parseCommandLine(argc, argv);
-
- // set up the window and database for our purposes
- // a lot of GL could be avoid through inventor, but its good to show as
- // an example
- Widget mainWindow = SoXt::init(argv[0]);
- if (mainWindow == NULL) {
- fprintf(stderr, "error initing SoXt\n");
- exit(1);
- }
-
- // create the root of the scenegraph
- SoSeparator *root = new SoSeparator;
- root->ref();
-
- // create the camera
- camera = new SoPerspectiveCamera;
- camera->ref();
- camera->farDistance = 100;
- camera->nearDistance = 0.0001;
- root->insertChild(camera, 0);
-
- // create our wuss version of a headlight
- light = new SoPointLight;
- root->insertChild(light, 1);
-
- // read in the scenegraph from a file
- SoSeparator *stuff = readivFile(filename);
- if (stuff == NULL) exit(1); // did not get a scenegraph
- root->addChild(stuff);
-
- readFile(animfile); // read in the animation file
- createSplines(); // create the splines
-
- // if we are not starting at the first frame, we have to figure out
- // which key frames we are between
- currentkey = 0;
- if (START) {
- frameNum = startFrame;
- for (int i = 0; i < keyframenum; i++) {
- if (keyFrames[currentkey + 1].frame <= frameNum) currentkey++;
- }
- } else {
- frameNum = 0; // starting at the begining
- }
-
- // create the Viewer
- SoXtRenderArea *rendArea = new SoXtRenderArea(mainWindow);
- rendArea->setAutoRedraw(FALSE);
- rendArea->setSceneGraph(root);
- rendArea->setTitle(argv[0]);
- rendArea->setSize(SbVec2s(xwidth, yheight));
- rendArea->show();
- SoXt::show(mainWindow);
-
- SbViewportRegion offViewport(xwidth, yheight);
- SoOffscreenRenderer *offrender = new SoOffscreenRenderer(offViewport);
- FILE *fp;
-
- XtAppContext context = SoXt::getAppContext();
- XEvent event;
-
- // this is the mother of all rendering loops
- while ( 1 ) {
- while(XtAppPending(context)) {
- SoXt::nextEvent(context, &event);
- SoXt::dispatchEvent(&event);
- }
-
- Animate(camera, light); // move the camera and the light
- rendArea->render();
-
- // if we are done, get out of the loop
- if ((currentkey == keyframenum - 1 ) || (END && (frameNum > endFrame)))
- break;
-
- // if we are saving the screen, do it
- if (save) {
- char filename[100];
- char num[10];
- int frame;
-
- frame = frameNum + saveNum -1;
- if (frame < 10)
- sprintf(num, "00%d", frame);
- else
- if (frame < 100)
- sprintf(num, "0%d", frame);
- else
- sprintf(num, "%d", frame);
-
- sprintf(filename, "animation%s.rgb", num);
- if (verbose) fprintf(stderr, " saving screen %d", frame);
-
- offrender->render(root);
- fp = OPEN(filename, "w");
- offrender->writeToRGB(fp);
- fclose(fp);
- } else {
- // pause, or it will go too fast
- sginap(naptime);
- }
-
- if (verbose) fprintf(stderr, "\n");
-
- }
-
- // if the user wanted us to print out the env file at the end
- if (printenv) {
- SoWriteAction wa;
- wa.apply(camera);
- }
-
- if (verbose) fprintf(stderr, "\n");
- }
-